package utils

// 条码打印保存到数据库操作模块

import (
	"asystem/cfg"
	"asystem/db"
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"regexp"
	"strings"
)

//var ret = make(chan map[string]interface{}, 10)
//
//func ReadResult() (retMap map[string]interface{}) {
//	for retMap = range ret {
//		if retMap["errMsg"] != "" {
//			retMap["errMsg"] = fmt.Sprintf("%v", retMap["errMsg"])
//			return retMap
//		} else {
//			retMap["success"] = "success"
//		}
//	}
//	return retMap
//}

// CodeToSql 打印条码并保存条码到数据库
func CodeToSql(code, bar string) error {
	/*
		参数说明：
			code：条码内容
			bar：条码后三位随机数
			printer：选择的打印机
			count：需要打印的条码份数
			wg：
			printChan: 并发控制 channel
		条码数据说明：
			序号头：codeSplt[0]
			配置Id: codeSplt[1]
			物料Id：codeSplt[2]
			客户Id: codeSplt[3]
			用户Id：codeSplt[4]
			时间戳：codeSplt[5]
			随机数：codeSplt[6]
	*/
	codeSplt := strings.Split(code+bar, ",")
	bomNameId, err := StrToInt(codeSplt[1])
	if err != nil {
		//c.JSON(200, gin.H{"success": "", "errMsg": fmt.Sprintf("打印失败，错误代码：%v", err)})
		return errors.New(fmt.Sprintf("打印失败，错误代码：%v", err))
	}
	mid, err := StrToInt(codeSplt[2])
	if err != nil {
		//c.JSON(200, gin.H{"success": "", "errMsg": fmt.Sprintf("打印失败，错误代码：%v", err)})
		return errors.New(fmt.Sprintf("打印失败，错误代码：%v", err))
	}
	cid, err := StrToInt(codeSplt[3])
	if err != nil {
		//c.JSON(200, gin.H{"success": "", "errMsg": fmt.Sprintf("打印失败，错误代码：%v", err)})
		return errors.New(fmt.Sprintf("打印失败，错误代码：%v", err))
	}
	uid, err := StrToInt(codeSplt[4])
	if err != nil {
		//c.JSON(200, gin.H{"success": "", "errMsg": fmt.Sprintf("打印失败，错误代码：%v", err)})
		return errors.New(fmt.Sprintf("打印失败，错误代码：%v", err))
	}
	// 获取打印配置相关信息
	// 先保存条码数据到数据库
	model := &db.Model{Code: &db.Code{
		UId:          uid,
		CId:          cid,
		MId:          mid,
		BomNamId:     bomNameId,
		BarCode:      code + bar,
		OutLibUserId: 0,
	}}
	if err = insertCodeToSql(model); err != nil {
		//c.JSON(200, gin.H{"success": "", "errMsg": fmt.Sprintf("%v", err)})
		return errors.New(fmt.Sprintf("%v", err))
	}
	return nil
}

// insertCodeToSql 插入条码数据到数据库
func insertCodeToSql(model *db.Model) error {
	if _, err := db.CodeSqlOpFunc("insert", model); err != nil {
		return errors.New(fmt.Sprintf("条码信息保存到数据库错误，打印出来的条码无效: %v", err))
	}
	return nil
}

// PrintCodeFunc 打印条码方法
func PrintCodeFunc(codeXml, printerId string) error {
	/*
		参数说明：
			code：打印的条码信息
			printerId: 前端提交的打印机Id,根据该Id 去数据库获取打印机信息
	*/
	var _, _, BtAddr = "", "", "" // todo 去掉了一个打印机地址信息
	pid, err := StrToInt(printerId)
	if err != nil {
		//c.JSON(200, gin.H{"success": "", "errMsg": fmt.Sprintf("打印失败，错误代码：%v", err)})
		return errors.New(fmt.Sprintf("打印失败，错误代码：%v", err))
	}
	// 读取配置文件
	pCfg, err := cfg.LoadCfg(cfg.FILEPATH)
	if err != nil {
		//c.JSON(200, gin.H{"success": "", "errMsg": fmt.Sprintf("打印失败，错误代码：%v", err)})
		return errors.New(fmt.Sprintf("打印失败，错误代码：%v", err))
	}
	// 根据打印机Id 获取打印机地址和BT服务器地址
	modelPt := &db.Model{Printer: &db.Printer{
		Pid: pid,
	}}
	printCfg, err := db.CodeSqlOpFunc("get", modelPt)
	if err != nil {
		//c.JSON(200, gin.H{"success": "", "errMsg": fmt.Sprintf("获取打印机配置错误，条码打印失败，错误代码：%v", err)})
		return errors.New(fmt.Sprintf("获取打印机配置错误，条码打印失败，错误代码：%v", err))
	}
	for _, val := range printCfg {
		//printAddr = val.PNetAddr
		BtAddr = val.BTSerAddr
	}
	//fmt.Println(printAddr)
	dataXml := `
		<?xml version="1.0" encoding="utf-8"?>
		<XMLScript Version="2.0">
		<Command Name="Job1">
		<Print>
		<Format>C:\Users\Administrator\Documents\bT\test.btw</Format>
		<RecordSet Name="testWithHeader" Type="btTextFile">
		<TextData>
		<![CDATA[A
		` + "\n" + codeXml + `
		]]>
		</TextData>
		</RecordSet>
		</Print>
		</Command>
		</XMLScript> 
	`
	// 发送 POST 请求开始打印  todo ——pCfg.CodeCfg.Company["lianli"]公司名应从前端传过来，此处不应写死
	if err = requestPostPrint(BtAddr, dataXml, pCfg.CodeCfg.ReHead); err != nil {
		fmt.Println("======================================>", err)
		return errors.New(fmt.Sprintf("%v", err))
	}
	return nil
}

// 发起请求开始打印条码
func requestPostPrint(bturl, codeXml, contentType string) error {
	/*
		参数说明：
			code：打印的条码信息
			copies：打印份数
			printChan：控制并发 channel
			codeReqUrl：扫描条码请求的 API 地址
			bturl： bt 服务器地址
			codeTitle：条码二维码头信息
			contentType：请求类型
	*/
	//reqData := make(map[string]interface{}, 0)
	//reqData["codeReqUrl"] = codeReqUrl
	//reqData["copies"] = copies
	//reqData["code"] = code
	//reqData["codeTitle"] = codeTitle
	//reqDatBytes, err := json.Marshal(reqData)
	//if err != nil {
	//	c.JSON(200, gin.H{"success": "", "errMsg": fmt.Sprintf("打印失败，错误代码：%v", err)})
	//	return
	//}
	post, err := http.Post(bturl, contentType, bytes.NewBuffer([]byte(codeXml)))
	if err != nil {
		//c.JSON(200, gin.H{"success": "", "errMsg": fmt.Sprintf("条码打印失败，发起 POST 提交数据失败，错误代码：%v", err)})
		return errors.New(fmt.Sprintf("条码打印失败，发起 POST 提交数据失败，错误代码：%v", err))
	}
	defer post.Body.Close()
	retbody, err := ioutil.ReadAll(post.Body)
	if err != nil {
		//c.JSON(200, gin.H{"success": "", "errMsg": fmt.Sprintf("读取 XML 数据错误，条码打印失败，错误代码：%v", err)})
		return errors.New(fmt.Sprintf("读取 XML 数据错误，条码打印失败，错误代码：%v", err))
	}
	// 开始解析返回的数据，确定是否打印成功
	if err = regexpBody(retbody); err != nil {
		//c.JSON(200, gin.H{"success": "", "errMsg": fmt.Sprintf("解析 XML 数据错误，条码打印失败，错误代码：%v", err)})
		return errors.New(fmt.Sprintf("解析 XML 数据错误，条码打印失败，错误代码：%v", err))
	} else {
		//c.JSON(200, gin.H{"success": "success", "errMsg": ""})
		return nil
	}
}

// 对 post 请求得到的 body 信息进行正常解析，拿到其中的文字内容
func regexpBody(body []byte) error {
	/*
		参数说明：
			body：读取到 bt 服务器返回的 body 信息，下面做正则匹配
			printChan：控制并发 channel
	*/
	reg := regexp.MustCompile("<Text>(?s:(.*?))。")
	if reg == nil {
		return errors.New(fmt.Sprintf("正则没有解析到任何内容，条码打印失败，请检查匹配规则!"))
	}
	result := reg.FindAllStringSubmatch(string(body[:]), -1)
	fmt.Println(result)
	if len(result) > 0 {
		rest := strings.Split(result[0][1], " ")
		if rest[0] == "BarTender" {
			return nil
		} else {
			return errors.New(fmt.Sprintf("条码打印失败,未解析到正确内容~!"))
		}
	} else {
		return errors.New(fmt.Sprintf("读取解析后的字符串切片数据错误，条码打印失败，请检查相关语法是否正确"))
	}
}
